const char *target)
{
char prefix[3];
- prefix[0] = from[0];
- prefix[1] = from[1];
- prefix[2] = '\0';
- from += 2;
- return g_strconcat ("deltas/", prefix, "/", from, "-", to, "/", target, NULL);
+ if (from == NULL)
+ {
+ prefix[0] = to[0];
+ prefix[1] = to[1];
+ prefix[2] = '\0';
+ to += 2;
+ return g_strconcat ("deltas/", prefix, "/", to, "/", target, NULL);
+ }
+ else
+ {
+ prefix[0] = from[0];
+ prefix[1] = from[1];
+ prefix[2] = '\0';
+ from += 2;
+ return g_strconcat ("deltas/", prefix, "/", from, "-", to, "/", target, NULL);
+ }
}
char *
/**
* ostree_diff_dirs:
* @flags: Flags
- * @a: First directory path
+ * @a: First directory path, or %NULL
* @b: First directory path
* @modified: (element-type OstreeDiffItem): Modified files
* @removed: (element-type Gio.File): Removed files
gs_unref_object GFileInfo *child_a_info = NULL;
gs_unref_object GFileInfo *child_b_info = NULL;
+ if (a == NULL)
+ {
+ if (!diff_add_dir_recurse (b, added, cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ goto out;
+ }
+
child_a_info = g_file_query_info (a, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
if (have_all)
{
g_debug ("Have all objects from static delta %s-%s part %u",
- from_revision, to_revision,
+ from_revision ? from_revision : "empty", to_revision,
i);
continue;
}
&from_revision, error))
goto out;
- if (from_revision && g_strcmp0 (from_revision, to_revision) != 0)
+ if (from_revision == NULL || g_strcmp0 (from_revision, to_revision) != 0)
{
if (!request_static_delta_superblock_sync (pull_data, from_revision, to_revision,
&delta_superblock, cancellable, error))
if (!delta_superblock)
{
- g_debug ("no delta superblock for %s-%s", from_revision, to_revision);
+ g_debug ("no delta superblock for %s-%s", from_revision ? from_revision : "empty", to_revision);
if (!scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT,
0, pull_data->cancellable, error))
goto out;
}
else
{
- g_debug ("processing delta superblock for %s-%s", from_revision, to_revision);
+ g_debug ("processing delta superblock for %s-%s", from_revision ? from_revision : "empty", to_revision);
if (!process_one_static_delta (pull_data, from_revision, to_revision,
delta_superblock,
cancellable, error))
gs_unref_hashtable GHashTable *modified_content_objects = NULL;
gs_unref_hashtable GHashTable *content_object_to_size = NULL;
- if (!ostree_repo_read_commit (repo, from, &root_from, NULL,
- cancellable, error))
- goto out;
+ if (from != NULL)
+ {
+ if (!ostree_repo_read_commit (repo, from, &root_from, NULL,
+ cancellable, error))
+ goto out;
+ }
if (!ostree_repo_read_commit (repo, to, &root_to, NULL,
cancellable, error))
goto out;
g_hash_table_add (modified_content_objects, objname);
}
- if (!ostree_repo_traverse_commit (repo, from, 0, &from_reachable_objects,
- cancellable, error))
- goto out;
+ if (from)
+ {
+ if (!ostree_repo_traverse_commit (repo, from, 0, &from_reachable_objects,
+ cancellable, error))
+ goto out;
+ }
if (!ostree_repo_traverse_commit (repo, to, 0, &to_reachable_objects,
cancellable, error))
const char *checksum;
OstreeObjectType objtype;
- if (g_hash_table_contains (from_reachable_objects, serialized_key))
+ if (from_reachable_objects && g_hash_table_contains (from_reachable_objects, serialized_key))
continue;
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
* ostree_repo_static_delta_generate:
* @self: Repo
* @opt: High level optimization choice
- * @from: ASCII SHA256 checksum of origin
+ * @from: ASCII SHA256 checksum of origin, or %NULL
* @to: ASCII SHA256 checksum of target
* @metadata: (allow-none): Optional metadata
* @params: (allow-none): Parameters, see below
* @cancellable: Cancellable
* @error: Error
*
- * Generate a lookaside "static delta" from @from which can generate
- * the objects in @to. This delta is an optimization over fetching
- * individual objects, and can be conveniently stored and applied
- * offline.
+ * Generate a lookaside "static delta" from @from (%NULL means
+ * from-empty) which can generate the objects in @to. This delta is
+ * an optimization over fetching individual objects, and can be
+ * conveniently stored and applied offline.
*
* The @params argument should be an a{sv}. The following attributes
* are known:
{
GDateTime *now = g_date_time_new_now_utc ();
/* floating */ GVariant *from_csum_v =
- ostree_checksum_to_bytes_v (from);
+ from ? ostree_checksum_to_bytes_v (from) : ot_gvariant_new_bytearray ((guchar *)"", 0);
/* floating */ GVariant *to_csum_v =
ostree_checksum_to_bytes_v (to);
+
delta_descriptor = g_variant_new ("(@(a(ss)a(say))t@ay@ay@" OSTREE_COMMIT_GVARIANT_STRING "ay"
"a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT
"@a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")",
/**
* ostree_repo_sign_delta:
* @self: Self
- * @from_commit: SHA256 of starting commit to sign
+ * @from_commit: SHA256 of starting commit to sign, or %NULL
* @to_commit: SHA256 of target commit to sign
* @key_id: Use this GPG key id
* @homedir: (allow-none): GPG home directory, or %NULL
static char **opt_key_ids;
static char *opt_gpg_homedir;
static char *opt_max_usize;
+static gboolean opt_empty;
#define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, GCancellable *cancellable, GError **error)
static GOptionEntry generate_options[] = {
{ "from", 0, 0, G_OPTION_ARG_STRING, &opt_from_rev, "Create delta from revision REV", "REV" },
+ { "empty", 0, 0, G_OPTION_ARG_NONE, &opt_empty, "Create delta from scratch", NULL },
{ "to", 0, 0, G_OPTION_ARG_STRING, &opt_to_rev, "Create delta to revision REV", "REV" },
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the delta with", "key-id"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "homedir"},
g_assert (opt_to_rev);
- if (opt_from_rev == NULL)
+ if (opt_empty)
+ {
+ from_source = NULL;
+ }
+ else if (opt_from_rev == NULL)
{
from_parent_str = g_strconcat (opt_to_rev, "^", NULL);
from_source = from_parent_str;
from_source = opt_from_rev;
}
- if (!ostree_repo_resolve_rev (repo, from_source, FALSE, &from_resolved, error))
- goto out;
+ if (from_source)
+ {
+ if (!ostree_repo_resolve_rev (repo, from_source, FALSE, &from_resolved, error))
+ goto out;
+ }
if (!ostree_repo_resolve_rev (repo, opt_to_rev, FALSE, &to_resolved, error))
goto out;
"max-usize", g_variant_new_uint32 (g_ascii_strtoull (opt_max_usize, NULL, 10)));
g_print ("Generating static delta:\n");
- g_print (" From: %s\n", from_resolved);
+ g_print (" From: %s\n", from_resolved ? from_resolved : "empty");
g_print (" To: %s\n", to_resolved);
if (!ostree_repo_static_delta_generate (repo, OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR,
from_resolved, to_resolved, NULL,
done
}
+origrev=$(ostree --repo=repo rev-parse test)
+
+ostree --repo=repo static-delta generate --empty --to=${origrev}
+ostree --repo=repo static-delta list | grep ${origrev} || exit 1
+
permuteDirectory 1 files
ostree --repo=repo commit -b test -s test --tree=dir=files
-ostree --repo=repo static-delta list
-origrev=$(ostree --repo=repo rev-parse test^)
newrev=$(ostree --repo=repo rev-parse test)
ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev}
+ostree --repo=repo static-delta list | grep ${origrev}-${newrev} || exit 1
+
origstart=$(echo ${origrev} | dd bs=1 count=2 2>/dev/null)
origend=$(echo ${origrev} | dd bs=1 skip=2 2>/dev/null)
assert_has_dir repo/deltas/${origstart}/${origend}-${newrev}
+assert_has_dir repo/deltas/${origstart}/${origend}
mkdir repo2
ostree --repo=repo2 init --mode=archive-z2
ostree --repo=repo2 static-delta apply-offline repo/deltas/${origstart}/${origend}-${newrev}
ostree --repo=repo2 fsck
ostree --repo=repo2 show ${newrev}
+
+mkdir repo3
+ostree --repo=repo3 init --mode=archive-z2
+ostree --repo=repo3 static-delta apply-offline repo/deltas/${origstart}/${origend}
+ostree --repo=repo3 fsck
+ostree --repo=repo3 show ${origrev}